#ifndef SIMPLE_TERMINAL_H
#define SIMPLE_TERMINAL_H

#include <errno.h>
#include <libgen.h>
#include <limits.h>
#include <locale.h>
#include <math.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>
#include <X11/X.h>
#include <X11/Xatom.h>
#include <X11/Xft/Xft.h>
#include <X11/XKBlib.h>
#include <X11/Xlib.h>

/// arg.h
/// ==========================================================================================================================================================================------
#ifndef ARG_H
#define ARG_H
char *argv0;
#define ARGBEGIN \
    for (argv0 = *argv, argv++, argc--; \
         argv[0] && argv[0][0] == '-' && argv[0][1]; argc--, argv++) { \
        char argc_; \
        char **argv_; \
        int brk_; \
        if (argv[0][1] == '-' && argv[0][2] == '\0') { \
            argv++; \
            argc--; \
            break; \
        } \
        int i_; \
        for (i_ = 1, brk_ = 0, argv_ = argv; argv[0][i_] && !brk_; i_++) { \
            if (argv_ != argv) \
                break; \
            argc_ = argv[0][i_]; \
            switch (argc_)

#define ARGEND \
    } \
    }

#define ARGC() argc_

#define EARGF(x) \
    ((argv[0][i_ + 1] == '\0' && argv[1] == NULL) \
         ? ((x), abort(), (char *)0) \
         : (brk_ = 1, (argv[0][i_ + 1] != '\0') ? (&argv[0][i_ + 1]) \
                                                : (argc--, argv++, argv[0])))

#define ARGF() \
    ((argv[0][i_ + 1] == '\0' && argv[1] == NULL) \
         ? (char *)0 \
         : (brk_ = 1, (argv[0][i_ + 1] != '\0') ? (&argv[0][i_ + 1]) \
                                                : (argc--, argv++, argv[0])))
#endif 
/// end arg.h

#define MIN(a, b)        ((a) < (b) ? (a) : (b))
#define MAX(a, b)        ((a) < (b) ? (b) : (a))
#define ARRAY_LEN(a)     (sizeof(a) / sizeof(a)[0])
#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
#define DIVCEIL(n, d)    (((n) + ((d) - 1))) / (d)
#define DEFAULT(a, b)    (a) = (a) ? (a) : (b)
#define LIMIT(x, a, b)   (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)

#define ATTRCMP(a, b) \
    ((a).mode != (b).mode || (a).fg != (b).fg || (a.bg) != (b).bg)

#define TIMEDIFF(t1, t2) \
    ((t1.tv_sec - t2.tv_sec) * 1000 + (t1.tv_nsec - t2.tv_nsec) / 1E16)

#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
#define TRUECOLOR(r, g, b)  (1 << 24 | (r) << 16 | (g) << 8 | (b))
#define IS_TRUECOLOR(x)     (1 << 24 & (x))
#ifndef STS_H
#define STS_H
enum Glyph_Attribute {
    G_A_Null = 0,
    G_A_Bold = 1 << 0,
    G_A_Faint = 1 << 1,
    G_A_Italic = 1 << 2,
    G_A_Underline = 1 << 3,

    G_A_Blink = 1 << 4,
    G_A_Reverse = 1 << 5,
    G_A_Invisible = 1 << 6,
    G_A_Struck = 1 << 7,
    G_A_Wrap = 1 << 8,

    G_A_Wide = 1 << 9,
    G_A_Wdummy = 1 << 10,
    G_A_BoxDraw = 1 << 11,
    G_A_Liga = 1 << 12,
    G_A_Bold_Faint = G_A_Bold | G_A_Faint,
};

enum Selection_Mode {
    S_M_Idle = 0,
    S_M_Empty = 1,
    S_M_Ready = 2
};

enum Selection_Type {
    S_T_Regular = 1,
    S_T_Rectangular = 2
};

enum Selection_Snap {
    S_S_Word = 1,
    S_S_Line = 2
};

typedef uint_least32_t Rune;

typedef struct {
    Rune u;              // char mode
    unsigned short mode; // attr flags
    uint32_t fg;         // foreground
    uint32_t bg;         // background
} ST_Glyph;              // Glyph conflict name with X11, so rename to ST_Glyph

typedef ST_Glyph *Line;  // using Line = ST_Glyph*

typedef union {          // union to struct
    int i;
    unsigned int ui;
    float f;
    void const *v;
    char const *s;

} Arg;

typedef struct {
    unsigned int mod;
    KeySym keysym;
    void (*func)(Arg const *);
    Arg const arg;
} Shortcut;

typedef struct {
    unsigned int mod;
    unsigned int button;
    void (*func)(Arg const *);
    Arg const arg;
    unsigned int release;
} MouseShortcut;

typedef struct {
    KeySym k;
    unsigned int mask;
    char *s;
    char appkey;
    char appcursor;
} Key;
#endif

#define XK_ANY_MOD    UINT_MAX
#define XK_NO_MOD     0
#define XK_SWITCH_MOD (1 << 13 | 1 << 14)

#define XEMBED_FOCUS_IN  4
#define XEMBED_FOCUS_OUT 5

#define IS_WMSET(flag) ((win.mode & (flag)) != 0)
#define TRUE_RED(x)    (((x) & 0xff0000) >> 8)
#define TRUE_GREEN(x)  (((x) & 0xff00))
#define TRUE_BLUE(x)   (((x) & 0xff) << 8)

typedef XftDraw *Draw;
typedef XftColor Color;
typedef XftGlyphFontSpec GlyphFontSpec;

typedef struct {
    int tw, th;
    int w, h;
    int ch, cw;
    int mode;
    int cursor;
} TermWindow;

typedef struct {
    Display *dpy;
    Colormap cmap;
    Window win;
    Drawable buf;
    GlyphFontSpec *specbuf;
    Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid;

    struct {
        XIM xim;
        XIC xic;
        XPoint spot;
        XVaNestedList spotlist;
    } ime;

    Draw draw;

    Visual *vis;
    XSetWindowAttributes attrs;

    int scr;
    int isfixed;
    int l, t;
    int gm;
} XWindow;

typedef struct {
    Atom xtarget;
    char *primary, *clipboard;
    struct timespec tclick1;
    struct timespec tclick2;
} XSelection;

typedef struct {
    int height, width;
    int ascent;
    int descent;
    int badslant;
    int badweight;
    short lbearing, rbearing;
    XftFont *match;
    FcFontSet *set;
    FcPattern *pattern;
} ST_Font; // Font is taken by X11 lib

typedef struct {
    Color *col;
    size_t collen;
    ST_Font font, bfont, ifont, ibfont;
    GC gc;
} DrawContext;

inline unsigned short sixd_to_16bit(int);
int xmake_glyph_fontspec(XftGlyphFontSpec *, ST_Glyph const *, int, int,
                                int);
void xdraw_glyph_fontspec(XftGlyphFontSpec const *, ST_Glyph, int, int,
                                 int);
void xdraw_glyph(ST_Glyph, int, int);
void xclear(int, int, int, int);
int xgeom_mask_to_gravity(int);
int xim_open(Display *);
void xim_instantiate(Display *, XPointer, XPointer);
void xim_destroy(XIM, XPointer, XPointer);

int xic_destroy(XIC, XPointer, XPointer);
void xinit(int, int);
void cresize(int, int);
void xresize(int, int);
void xhints(void);

int xload_color(int, char const *, Color *);
void xload_alpha(void);
int xload_font(Font *, FcPattern *);
void xload_fonts(char const *, double);
void xunload_font(Font *);
void xunload_fonts(void);

void xsetenv(void);
void xset_urgency(int);
int ev_col(XEvent *);
int ev_row(XEvent *);

void expose(XEvent *);
void visibility(XEvent *);
void unmap(XEvent *);
void kpress(XEvent *);
void cmessage(XEvent *);

void resize(XEvent *);
void focus(XEvent *);
unsigned int button_mask(unsigned int);
int mouse_action(XEvent *, unsigned int);

void brelease(XEvent *);
void bpress(XEvent *);
void bmotion(XEvent *);

void prop_notify(XEvent *);
void sel_notify(XEvent *);
void sel_clear(XEvent *);
void sel_request(XEvent *);
void set_sel(char *, Time);
void mouse_sel(XEvent *, int);
void mouse_report(XEvent *);
char *kmap(KeySym, unsigned int);
int match(unsigned int, unsigned int);

void run(void);

DrawContext dc;
XWindow xw;
XSelection xsel;
TermWindow win;

enum Font_Ring_Cache {
    FRC_Normal,
    FRC_Italic,
    FRC_Bold,
    FRC_Italicbold
};

typedef struct {
    XftFont *font;
    int flags;
    Rune unicodep;
} Fontcache;

Fontcache *frc = NULL;
int frclen = 0;
int frccap = 0;
char *usedfont = NULL;
double usedfontsize = 0;
double defaultfontsize = 0;

char *opt_alpha = NULL;
char *opt_class = NULL;
char **opt_cmd = NULL;
char *opt_embed = NULL;
char *opt_font = NULL;
char *opt_io = NULL;
char *opt_line = NULL;
char *opt_name = NULL;
char *opt_title = NULL;

int focused = 0;

int oldbutton = 3;    /* button event on startup: 3 = release */
unsigned int buttons; /* bit field of pressed buttons */

enum Win_Mode {
    // TODO:
    W_M_Visible = 1 << 0,
    W_M_Focused = 1 << 1,
    W_M_Appkeypad = 1 << 2,
    W_M_MouseBtn = 1 << 3,
    W_M_MouseMotion = 1 << 4,

    W_M_Reverse = 1 << 5,
    W_M_KbdLock = 1 << 6,
    W_M_Hide = 1 << 7,
    W_M_AppCursor = 1 << 8,
    W_M_MouseSgr = 1 << 9,

    W_M_8Bit = 1 << 10,
    W_M_Blink = 1 << 11,
    W_M_FBlink = 1 << 12,
    W_M_Focus = 1 << 13,
    W_M_MouseX10 = 1 << 14,
    W_M_MouseMany = 1 << 15,
    W_M_BrcktPaste = 1 << 16,
    W_M_NumLock = 1 << 17,
    W_M_Mouse = W_M_MouseBtn | W_M_MouseMotion | W_M_MouseX10 | W_M_MouseMany,
};

void xbell(void);
void xclip_copy(void);
void xdraw_cursor(int, int, ST_Glyph, int, int, ST_Glyph);
void xdraw_line(Line, int, int, int);
void xfinish_draw(void);

void xload_cols(void);
int xset_color_name(int, char const *);
int xget_color(int, unsigned char *, unsigned char *, unsigned char *);
void xset_icon_title(char *);
void xset_title(char *);
int xset_cursor(int);

void xset_mode(int, unsigned int);
void xset_pointer_motion(int);
void xset_sel(char *);
int xstart_draw(void);
void xximspot(int, int);

#define UTF_INVALID  0xFFFD
#define UTF_SIZE     4 // macro to size_t
#define ESC_BUF_SIZE (128 * UTF_SIZE)
#define ESC_ARG_SIZE 16
#define STR_BUF_SIZE ESC_BUF_SIZE
#define STR_ARG_SIZE ESC_ARG_SIZE
#define HISTSIZE     2000

#define IS_TMSET(flag)  ((term.mode & (flag)) != 0)
#define IS_CONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == 0x7f)
#define IS_CONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
#define IS_CONTROL(c)   (IS_CONTROLC0(c) || IS_CONTROLC1(c))
#define IS_DELIM(u)     (u && wcschr(word_delimiters, u))

#define TLINE(y) \
    ((y) < term.scr \
         ? term.hist[((y) + term.histi - term.scr + HISTSIZE + 1) % HISTSIZE] \
         : term.line[(y) - term.scr])

#define TLINE_HIST(y) \
    ((y) <= HISTSIZE - term.row + 2 \
         ? term.hist[(y)] \
         : term.line[(y - HISTSIZE + term.row - 3)])

enum Term_Mode {
    T_M_Wrap = 1 << 0,
    T_M_Insert = 1 << 1,
    T_M_AltScreen = 1 << 2,
    T_M_Crlf = 1 << 3,
    T_M_Echo = 1 << 4,
    T_M_Print = 1 << 5,
    T_M_Utf8 = 1 << 6,
};

enum Cursor_Movement {
    C_M_Save,
    C_M_Load,
};

enum Cursor_State {
    C_S_Default = 0,
    C_S_WrapNext = 1,
    C_S_Origin = 2
};

enum Charset {
    CS_Graphic0,
    CS_Graphic1,
    CS_UK,
    CS_USA,
    CS_Multi,
    CS_GER,
    CS_FIN,
};

enum Escape_State {
    ESC_Start = 1,
    ESC_Csi = 2,
    ESC_Str = 4,
    ESC_AltCharset = 8,
    ESC_StrEnd = 16,
    ESC_Test = 32,
    ESC_Utf8 = 64,
};

typedef struct {
    ST_Glyph attr; // current char attributes
    int x, y;
    char state;
} TCursor;

typedef struct {
    int mode, type, snap, alt;

    struct {
        int x, y;
    } nb, ne, ob, oe;
} Selection;

typedef struct {
    int row;             /* nb row */
    int col;             /* nb col */
    int maxcol;
    Line *line;          /* screen */
    Line *alt;           /* alternate screen */
    Line hist[HISTSIZE]; /* history buffer */
    int histi;           /* history index */
    int scr;             /* scroll back */
    int *dirty;          /* dirtyness of lines */
    TCursor c;           /* cursor */
    int ocx;             /* old cursor col */
    int ocy;             /* old cursor row */
    int top;             /* top    scroll limit */
    int bot;             /* bottom scroll limit */
    int mode;            /* terminal mode flags */
    int esc;             /* escape state flags */
    char trantbl[4];     /* charset table translation */
    int charset;         /* current charset */
    int icharset;        /* selected charset for sequence */
    int *tabs;
    Rune lastc; /* last printed char outside of sequence, 0 if control */
} Term;

typedef struct {
    char buf[ESC_BUF_SIZE];
    size_t len;
    char priv;
    int arg[ESC_ARG_SIZE];
    int narg;
    char mode[2];
} CSIEscape;

typedef struct {
    char type;
    char *buf;
    size_t size, len;
    char *args[STR_ARG_SIZE];
    int narg;
} STREscape;

// global vars
Term term;
Selection sel;
CSIEscape csiescseq;
STREscape strescseq;
int iofd = 1;
int cmdfd;
pid_t pid;

unsigned char const utfbyte[UTF_SIZE + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
unsigned char const utfmask[UTF_SIZE + 1] = {0xC0, 0x80, 0xE0, 0xF0,
                                                    0xF8};
Rune const utfmin[UTF_SIZE + 1] = {0, 0, 0x80, 0x800, 0x10000};
Rune const utfmax[UTF_SIZE + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF,
                                          0x10FFFF};

// end global vars

void die(char const *, ...);
void redraw(void);
void draw(void);

void externalpipe(Arg const *);
void kscrolldown(Arg const *);
void kscrollup(Arg const *);

void print_screen(Arg const *);
void print_sel(Arg const *);
void send_break(Arg const *);
void toggle_printer(Arg const *);

int terminal_attrset(int);
int terminal_new(int, int);
int terminal_resize(int, int);

int terminal_set_dirt_attr(int);

void tty_hangup(void);
int tty_new(char const *, char *, char const *, char **);
size_t tty_read(void);
void tty_resize(int, int);
void tty_write(char const *, size_t, int);

void reset_title(void);

void selclear(void);
void sel_init(void);
void sel_start(int, int, int);
void sel_extend(int, int, int, int);

int selected(int, int);
char *get_sel(void);

size_t utf8_encode(Rune, char *);

void *xmalloc(size_t);
void *xrealloc(void *, size_t); // what does it mean x
char *xstrdup(char const *);

void clipcopy(Arg const *);
void clippaste(Arg const *);
void numlock(Arg const *);
void selpaste(Arg const *);
void zoom(Arg const *); // zoom level ?
void zoomabs(Arg const *);
void zoomreset(Arg const *);
void ttysend(Arg const *);

void exec_sh(char *, char **);
void stty(char **);
void sigchld(int);
void tty_write_raw(char const *, size_t);

void csidump(void);
void csihandle(void);
void csiparse(void);
void csireset(void);
void osc_color_response(int, int, int);
void esc_handle(unsigned char);
void str_dump(void);
void str_handle(void);
void str_parse(void);
void str_reset(void);

void tprinter(char *, size_t);
void tdump_sel(void);

void tdump_line(int);

void tdump(void);

void tclear_region(int, int, int, int);
void tcursor(int);
void tdelete_char(int);
void tdelete_line(int);
void tinsert_blank(int);
void tinsert_blankline(int);
int tline_len(int n);
void tmoveto(int, int);
void tmoveato(int, int);
void tnew_line(int);
void tput_tab(int);
void tputc(Rune);
void treset(void);
int isboxdraw(Rune);
void tscrollup(int, int, int);
void tscrolldown(int, int, int);
void tset_attr(int const *, int);
void tset_char(Rune, ST_Glyph const *, int, int);
void tset_dirt(int, int);
void tset_scroll(int, int);
void tswap_screen(void);
void tset_mode(int, int, int const *, int);
int twrite(char const *, int, int);
void tfull_dirt(void);
void tcontrol_code(unsigned char);
void tdectest(char);
void tdefutf8(char);
int32_t tdef_color(int const *, int *, int);
void tdef_tran(char);
void tstr_sequence(unsigned char);

void draw_region(int, int, int, int);

void sel_normalize(void);
void sel_scroll(int, int);
void sel_snap(int *, int *, int);

size_t utf8_decode(char const *, Rune *, size_t);
Rune utf8_decodebyte(char, size_t *);
char utf8_encodebyte(Rune, size_t);
size_t utf8_validate(Rune *, size_t);

char *base64dec(char const *);
char base64dec_getc(char const **);

ssize_t xwrite(int, char const *, size_t);
int tline_hist_len(int);
float clamp(float value, float lower, float upper);
void changealpha(Arg const *);
/// Config Space
/// ===========================================================================================
#ifndef CONFIG_H
#define CONFIG_H
#include <X11/cursorfont.h>
#include <X11/keysym.h>
#include <X11/X.h>
#include <X11/Xatom.h>
#include <X11/Xft/Xft.h>
#include <X11/XKBlib.h>
#include <X11/Xlib.h>
/* See LICENSE file for copyright and license details. */

/*
 * appearance
 *
 * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
 */
char *font = "Source Code Pro:pixelsize=28:antialias=true:autohint=true";
char *font2[] = {
    "NotoColorEmoji:pixelsize=10:antialias=true:autohint=true"};
int borderpx = 2;

/*
 * What program is execed by st depends of these precedence rules:
 * 1: program passed with -e
 * 2: scroll and/or utmp
 * 3: SHELL environment variable
 * 4: value of shell in /etc/passwd
 * 5: value of shell in config.h
 */
char *shell = "/bin/bash";
char *utmp = NULL;
/* scroll program: to enable use a string like "scroll" */
char *scroll = NULL;
char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";

/* identification sequence returned in DA and DECID */
char *vtiden = "\033[?6c";

/* Kerning / character bounding-box multipliers */
float cwscale = 1.0;
float chscale = 1.0;

/*
 * word delimiter string
 *
 * More advanced example: L" `'\"()[]{}"
 */
wchar_t *worddelimiters = L" ";

/* selection timeouts (in milliseconds) */
unsigned int doubleclicktimeout = 300;
unsigned int tripleclicktimeout = 600;

/* alt screens */
int allowaltscreen = 1;

/* allow certain non-interactive (insecure) window operations such as:
   setting the clipboard text */
int allowwindowops = 0;

/*
 * draw latency range in ms - from new content/keypress/etc until drawing.
 * within this range, st draws when content stops arriving (idle). mostly it's
 * near minlatency, but it waits longer for slow updates to avoid partial draw.
 * low minlatency will tear/flicker more, as it can "detect" idle too early.
 */
double minlatency = 8;
double maxlatency = 33;

/*
 * blinking timeout (set to 0 to disable blinking) for the terminal blinking
 * attribute.
 */
unsigned int blinktimeout = 800;

/*
 * thickness of underline and bar cursors
 */
unsigned int cursorthickness = 2;

/*
 * 1: render most of the lines/blocks characters without using the font for
 *    perfect alignment between cells (U2500 - U259F except dashes/diagonals).
 *    Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored.
 * 0: disable (render all U25XX glyphs normally from the font).
 */
int const boxdraw = 1;
int const boxdraw_bold = 0;

/* braille (U28XX):  1: render as adjacent "pixels",  0: use font */
int const boxdraw_braille = 0;

/*
 * bell volume. It must be a value between -100 and 100. Use 0 for disabling
 * it
 */
int bellvolume = 0;

/* default TERM value */
char *termname = "st-256color";

/*
 * spaces per tab
 *
 * When you are changing this value, don't forget to adapt the »it« value in
 * the st.info and appropriately install the st.info in the environment where
 * you use this st version.
 *
 *	it#$tabspaces,
 *
 * Secondly make sure your kernel is not expanding tabs. When running `stty
 * -a` »tab0« should appear. You can tell the terminal to not expand tabs by
 *  running following command:
 *
 *	stty tabs
 */
unsigned int tabspaces = 8;

/* bg opacity */
float alpha = 0.8;
float alphaOffset = 0.0;
float alphaUnfocus;

/* Terminal colors (16 first used in escape sequence) */
char const *colorname[] = {
    "#282828", /* hard contrast: #1d2021 / soft contrast: #32302f */
    "#cc241d", "#98971a", "#d79921", "#458588", "#b16286", "#689d6a", "#a89984",
    "#928374", "#fb4934", "#b8bb26", "#fabd2f", "#83a598", "#d3869b", "#8ec07c",
    "#ebdbb2", [255] = 0,
    /* more colors can be added after 255 to use with DefaultXX */
    "#add8e6", /* 256 -> cursor */
    "#555555", /* 257 -> rev cursor*/
    "#282828", /* 258 -> bg */
    "#ebdbb2", /* 259 -> fg */
};

/*
 * Default colors (colorname index)
 * foreground, background, cursor, reverse cursor
 */
unsigned int defaultfg = 259;
unsigned int defaultbg = 258;
unsigned int defaultcs = 256;
unsigned int defaultrcs = 257;
unsigned int background = 258;

/*
 * Default shape of cursor
 * 2: Block ("█")
 * 4: Underline ("_")
 * 6: Bar ("|")
 * 7: Snowman ("☃")
 */
unsigned int cursorshape = 2;

/*
 * Default columns and rows numbers
 */

unsigned int cols = 80;
unsigned int rows = 24;

/*
 * Default colour and shape of the mouse cursor
 */
unsigned int mouseshape = XC_xterm;
unsigned int mousefg = 7;
unsigned int mousebg = 0;

/*
 * Color used to display font attributes when fontconfig selected a font which
 * doesn't match the ones requested.
 */
unsigned int defaultattr = 11;

/*
 * Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set).
 * Note that if you want to use ShiftMask with selmasks, set this to an other
 * modifier, set to 0 to not use it.
 */
unsigned int forcemousemod = ShiftMask;

/*
 * Xresources preferences to load at startup
 */
// ResourcePref resources[] = {
//     {"font", STRING, &font},
//     {"fontalt0", STRING, &font2[0]},
//     {"color0", STRING, &colorname[0]},
//     {"color1", STRING, &colorname[1]},
//     {"color2", STRING, &colorname[2]},
//     {"color3", STRING, &colorname[3]},
//     {"color4", STRING, &colorname[4]},
//     {"color5", STRING, &colorname[5]},
//     {"color6", STRING, &colorname[6]},
//     {"color7", STRING, &colorname[7]},
//     {"color8", STRING, &colorname[8]},
//     {"color9", STRING, &colorname[9]},
//     {"color10", STRING, &colorname[10]},
//     {"color11", STRING, &colorname[11]},
//     {"color12", STRING, &colorname[12]},
//     {"color13", STRING, &colorname[13]},
//     {"color14", STRING, &colorname[14]},
//     {"color15", STRING, &colorname[15]},
//     {"background", STRING, &colorname[258]},
//     {"foreground", STRING, &colorname[259]},
//     {"cursorColor", STRING, &colorname[256]},
//     {"termname", STRING, &termname},
//     {"shell", STRING, &shell},
//     {"minlatency", INTEGER, &minlatency},
//     {"maxlatency", INTEGER, &maxlatency},
//     {"blinktimeout", INTEGER, &blinktimeout},
//     {"bellvolume", INTEGER, &bellvolume},
//     {"tabspaces", INTEGER, &tabspaces},
//     {"borderpx", INTEGER, &borderpx},
//     {"cwscale", FLOAT, &cwscale},
//     {"chscale", FLOAT, &chscale},
//     {"alpha", FLOAT, &alpha},
//     {"alphaOffset", FLOAT, &alphaOffset},
// };

/*
 * Internal mouse shortcuts.
 * Beware that overloading Button1 will disable the selection.
 */
MouseShortcut mshortcuts[] = {
    /* mask                 button   function        argument       release */
    {XK_NO_MOD, Button4, kscrollup, {.i = 1}},
    {XK_NO_MOD, Button5, kscrolldown, {.i = 1}},
    {XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1},
    {ShiftMask, Button4, ttysend, {.s = "\033[5;2~"}},
    {XK_ANY_MOD, Button4, ttysend, {.s = "\031"}},
    {ShiftMask, Button5, ttysend, {.s = "\033[6;2~"}},
    {XK_ANY_MOD, Button5, ttysend, {.s = "\005"}},
};

/* Internal keyboard shortcuts. */
#define MODKEY  Mod1Mask
#define TERMMOD (Mod1Mask | ShiftMask)

char *openurlcmd[] = {"/bin/sh", "-c", "st-urlhandler -o",
                             "externalpipe", NULL};
char *copyurlcmd[] = {"/bin/sh", "-c", "st-urlhandler -c",
                             "externalpipe", NULL};
char *copyoutput[] = {"/bin/sh", "-c", "st-copyout", "externalpipe",
                             NULL};

Shortcut shortcuts[] = {
    /* mask                 keysym          function        argument */
    {XK_ANY_MOD, XK_Break, send_break, {.i = 0}},
    {ControlMask, XK_Print, toggle_printer, {.i = 0}},
    {ShiftMask, XK_Print, print_screen, {.i = 0}},
    {XK_ANY_MOD, XK_Print, print_sel, {.i = 0}},
    {TERMMOD, XK_Prior, zoom, {.f = +1}},
    {TERMMOD, XK_Next, zoom, {.f = -1}},
    {TERMMOD, XK_Home, zoomreset, {.f = 0}},
    {TERMMOD, XK_C, clipcopy, {.i = 0}},
    {TERMMOD, XK_V, clippaste, {.i = 0}},
    {MODKEY, XK_c, clipcopy, {.i = 0}},
    {ShiftMask, XK_Insert, clippaste, {.i = 0}},
    {MODKEY, XK_v, clippaste, {.i = 0}},
    {ShiftMask, XK_Insert, selpaste, {.i = 0}},
    {TERMMOD, XK_Num_Lock, numlock, {.i = 0}},
    {ShiftMask, XK_Page_Up, kscrollup, {.i = -1}},
    {ShiftMask, XK_Page_Down, kscrolldown, {.i = -1}},
    {MODKEY, XK_Page_Up, kscrollup, {.i = -1}},
    {MODKEY, XK_Page_Down, kscrolldown, {.i = -1}},
    {MODKEY, XK_k, kscrollup, {.i = 1}},
    {MODKEY, XK_j, kscrolldown, {.i = 1}},
    {MODKEY, XK_Up, kscrollup, {.i = 1}},
    {MODKEY, XK_Down, kscrolldown, {.i = 1}},
    {MODKEY, XK_u, kscrollup, {.i = -1}},
    {MODKEY, XK_d, kscrolldown, {.i = -1}},
    {MODKEY, XK_s, changealpha, {.f = -0.05}},
    {MODKEY, XK_a, changealpha, {.f = +0.05}},
    {TERMMOD, XK_Up, zoom, {.f = +1}},
    {TERMMOD, XK_Down, zoom, {.f = -1}},
    {TERMMOD, XK_K, zoom, {.f = +1}},
    {TERMMOD, XK_J, zoom, {.f = -1}},
    {TERMMOD, XK_U, zoom, {.f = +2}},
    {TERMMOD, XK_D, zoom, {.f = -2}},
    {MODKEY, XK_l, externalpipe, {.v = openurlcmd}},
    {MODKEY, XK_y, externalpipe, {.v = copyurlcmd}},
    {MODKEY, XK_o, externalpipe, {.v = copyoutput}},
};

/*
 * Special keys (change & recompile st.info accordingly)
 *
 * Mask value:
 * * Use XK_ANY_MOD to match the key no matter modifiers state
 * * Use XK_NO_MOD to match the key alone (no modifiers)
 * appkey value:
 * * 0: no value
 * * > 0: keypad application mode enabled
 * *   = 2: term.numlock = 1
 * * < 0: keypad application mode disabled
 * appcursor value:
 * * 0: no value
 * * > 0: cursor application mode enabled
 * * < 0: cursor application mode disabled
 *
 * Be careful with the order of the definitions because st searches in
 * this table sequentially, so any XK_ANY_MOD must be in the last
 * position for a key.
 */

/*
 * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF)
 * to be mapped below, add them to this array.
 */
KeySym mappedkeys[] = {static_cast<KeySym>(-1)};

/*
 * State bits to ignore when matching key or button events.  By default,
 * numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored.
 */
unsigned int ignoremod = Mod2Mask | XK_SWITCH_MOD;

/*
 * This is the huge key array which defines all compatibility to the Linux
 * world. Please decide about changes wisely.
 */
Key key[] = {
    /* keysym           mask            string      appkey appcursor */
    {XK_KP_Home, ShiftMask, "\033[2J", 0, -1},
    {XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1},
    {XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1},
    {XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1},
    {XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0},
    {XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1},
    {XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1},
    {XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0},
    {XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1},
    {XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1},
    {XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0},
    {XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1},
    {XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1},
    {XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0},
    {XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1},
    {XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1},
    {XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0},
    {XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
    {XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0},
    {XK_KP_End, ControlMask, "\033[J", -1, 0},
    {XK_KP_End, ControlMask, "\033[1;5F", +1, 0},
    {XK_KP_End, ShiftMask, "\033[K", -1, 0},
    {XK_KP_End, ShiftMask, "\033[1;2F", +1, 0},
    {XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0},
    {XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0},
    {XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0},
    {XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0},
    {XK_KP_Insert, ShiftMask, "\033[4l", -1, 0},
    {XK_KP_Insert, ControlMask, "\033[L", -1, 0},
    {XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0},
    {XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
    {XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
    {XK_KP_Delete, ControlMask, "\033[M", -1, 0},
    {XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0},
    {XK_KP_Delete, ShiftMask, "\033[2K", -1, 0},
    {XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0},
    {XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0},
    {XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
    {XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0},
    {XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0},
    {XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0},
    {XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0},
    {XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0},
    {XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0},
    {XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0},
    {XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0},
    {XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0},
    {XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0},
    {XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0},
    {XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0},
    {XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0},
    {XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0},
    {XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0},
    {XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0},
    {XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0},
    {XK_Up, ShiftMask, "\033[1;2A", 0, 0},
    {XK_Up, Mod1Mask, "\033[1;3A", 0, 0},
    {XK_Up, ShiftMask | Mod1Mask, "\033[1;4A", 0, 0},
    {XK_Up, ControlMask, "\033[1;5A", 0, 0},
    {XK_Up, ShiftMask | ControlMask, "\033[1;6A", 0, 0},
    {XK_Up, ControlMask | Mod1Mask, "\033[1;7A", 0, 0},
    {XK_Up, ShiftMask | ControlMask | Mod1Mask, "\033[1;8A", 0, 0},
    {XK_Up, XK_ANY_MOD, "\033[A", 0, -1},
    {XK_Up, XK_ANY_MOD, "\033OA", 0, +1},
    {XK_Down, ShiftMask, "\033[1;2B", 0, 0},
    {XK_Down, Mod1Mask, "\033[1;3B", 0, 0},
    {XK_Down, ShiftMask | Mod1Mask, "\033[1;4B", 0, 0},
    {XK_Down, ControlMask, "\033[1;5B", 0, 0},
    {XK_Down, ShiftMask | ControlMask, "\033[1;6B", 0, 0},
    {XK_Down, ControlMask | Mod1Mask, "\033[1;7B", 0, 0},
    {XK_Down, ShiftMask | ControlMask | Mod1Mask, "\033[1;8B", 0, 0},
    {XK_Down, XK_ANY_MOD, "\033[B", 0, -1},
    {XK_Down, XK_ANY_MOD, "\033OB", 0, +1},
    {XK_Left, ShiftMask, "\033[1;2D", 0, 0},
    {XK_Left, Mod1Mask, "\033[1;3D", 0, 0},
    {XK_Left, ShiftMask | Mod1Mask, "\033[1;4D", 0, 0},
    {XK_Left, ControlMask, "\033[1;5D", 0, 0},
    {XK_Left, ShiftMask | ControlMask, "\033[1;6D", 0, 0},
    {XK_Left, ControlMask | Mod1Mask, "\033[1;7D", 0, 0},
    {XK_Left, ShiftMask | ControlMask | Mod1Mask, "\033[1;8D", 0, 0},
    {XK_Left, XK_ANY_MOD, "\033[D", 0, -1},
    {XK_Left, XK_ANY_MOD, "\033OD", 0, +1},
    {XK_Right, ShiftMask, "\033[1;2C", 0, 0},
    {XK_Right, Mod1Mask, "\033[1;3C", 0, 0},
    {XK_Right, ShiftMask | Mod1Mask, "\033[1;4C", 0, 0},
    {XK_Right, ControlMask, "\033[1;5C", 0, 0},
    {XK_Right, ShiftMask | ControlMask, "\033[1;6C", 0, 0},
    {XK_Right, ControlMask | Mod1Mask, "\033[1;7C", 0, 0},
    {XK_Right, ShiftMask | ControlMask | Mod1Mask, "\033[1;8C", 0, 0},
    {XK_Right, XK_ANY_MOD, "\033[C", 0, -1},
    {XK_Right, XK_ANY_MOD, "\033OC", 0, +1},
    {XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0},
    {XK_Return, Mod1Mask, "\033\r", 0, 0},
    {XK_Return, XK_ANY_MOD, "\r", 0, 0},
    {XK_Insert, ShiftMask, "\033[4l", -1, 0},
    {XK_Insert, ShiftMask, "\033[2;2~", +1, 0},
    {XK_Insert, ControlMask, "\033[L", -1, 0},
    {XK_Insert, ControlMask, "\033[2;5~", +1, 0},
    {XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
    {XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
    {XK_Delete, ControlMask, "\033[M", -1, 0},
    {XK_Delete, ControlMask, "\033[3;5~", +1, 0},
    {XK_Delete, ShiftMask, "\033[2K", -1, 0},
    {XK_Delete, ShiftMask, "\033[3;2~", +1, 0},
    {XK_Delete, XK_ANY_MOD, "\033[P", -1, 0},
    {XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
    {XK_BackSpace, XK_NO_MOD, "\177", 0, 0},
    {XK_BackSpace, Mod1Mask, "\033\177", 0, 0},
    {XK_Home, ShiftMask, "\033[2J", 0, -1},
    {XK_Home, ShiftMask, "\033[1;2H", 0, +1},
    {XK_Home, XK_ANY_MOD, "\033[H", 0, -1},
    {XK_Home, XK_ANY_MOD, "\033[1~", 0, +1},
    {XK_End, ControlMask, "\033[J", -1, 0},
    {XK_End, ControlMask, "\033[1;5F", +1, 0},
    {XK_End, ShiftMask, "\033[K", -1, 0},
    {XK_End, ShiftMask, "\033[1;2F", +1, 0},
    {XK_End, XK_ANY_MOD, "\033[4~", 0, 0},
    {XK_Prior, ControlMask, "\033[5;5~", 0, 0},
    {XK_Prior, ShiftMask, "\033[5;2~", 0, 0},
    {XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
    {XK_Next, ControlMask, "\033[6;5~", 0, 0},
    {XK_Next, ShiftMask, "\033[6;2~", 0, 0},
    {XK_Next, XK_ANY_MOD, "\033[6~", 0, 0},
    {XK_F1, XK_NO_MOD, "\033OP", 0, 0},
    {XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0},
    {XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0},
    {XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0},
    {XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0},
    {XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0},
    {XK_F2, XK_NO_MOD, "\033OQ", 0, 0},
    {XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0},
    {XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0},
    {XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0},
    {XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0},
    {XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0},
    {XK_F3, XK_NO_MOD, "\033OR", 0, 0},
    {XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0},
    {XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0},
    {XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0},
    {XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0},
    {XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0},
    {XK_F4, XK_NO_MOD, "\033OS", 0, 0},
    {XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0},
    {XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0},
    {XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0},
    {XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0},
    {XK_F5, XK_NO_MOD, "\033[15~", 0, 0},
    {XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0},
    {XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0},
    {XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0},
    {XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0},
    {XK_F6, XK_NO_MOD, "\033[17~", 0, 0},
    {XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0},
    {XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0},
    {XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0},
    {XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0},
    {XK_F7, XK_NO_MOD, "\033[18~", 0, 0},
    {XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0},
    {XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0},
    {XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0},
    {XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0},
    {XK_F8, XK_NO_MOD, "\033[19~", 0, 0},
    {XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0},
    {XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0},
    {XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0},
    {XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0},
    {XK_F9, XK_NO_MOD, "\033[20~", 0, 0},
    {XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0},
    {XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0},
    {XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0},
    {XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0},
    {XK_F10, XK_NO_MOD, "\033[21~", 0, 0},
    {XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0},
    {XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0},
    {XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0},
    {XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0},
    {XK_F11, XK_NO_MOD, "\033[23~", 0, 0},
    {XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0},
    {XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0},
    {XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0},
    {XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0},
    {XK_F12, XK_NO_MOD, "\033[24~", 0, 0},
    {XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0},
    {XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0},
    {XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0},
    {XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0},
    {XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0},
    {XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0},
    {XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0},
    {XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0},
    {XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0},
    {XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0},
    {XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0},
    {XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0},
    {XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0},
    {XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0},
    {XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0},
    {XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0},
    {XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0},
    {XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0},
    {XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0},
    {XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0},
    {XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0},
    {XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0},
    {XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0},
    {XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0},
    {XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0},
    {XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0},
    {XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0},
};

/*
 * Selection types' masks.
 * Use the same masks as usual.
 * Button1Mask is always unset, to make masks match between ButtonPress.
 * ButtonRelease and MotionNotify.
 * If no match is found, regular selection is used.
 */
unsigned int selmasks[] = {
    [S_T_Regular] = Mod1Mask,
};

/*
 * Printable characters in ASCII, used to estimate the advance width
 * of single wide characters.
 */
char ascii_printable[] = " !\"#$%&'()*+,-./0123456789:;<=>?"
                                "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
                                "`abcdefghijklmnopqrstuvwxyz{|}~";
#endif 
#endif // header file protect
